/* * File: PWMfunctions.c * Author: Jay Burns * * Created on April 3, 2012, 9:47 PM */ /* * README * * There are four functions you need to call to effectively use the PWM code. * First, call initializePWMcapture() and initializePWMoutput(). This will * setup the control registers and timers so input and output is ready to go. Then, in your while loop, * call getPWM(); This will read the PWM values. They are stored in: * * CH1value * CH2value * CH3value * CH4value * These are all values of 0 to 100. * * CH5status * CH5status is either 1 or 0. I suggest your main looking something like this: * * int main(void) { initializePWMcapture(); initializePWMoutput(); while(1) { getPWM(); if (CH5status == 1) { setPower(75, 74, 76, 72); //This is just an example output to the motors. Remember, it's } //setPower(motor1, motor2, motor3, motor4) else if (CH5status == 0) { setPower(0, 0, 0, 0); } } }. */ // Function Prototypes void getPWM(void); void initializePWMcapture(void); void initializePWMoutput(void); void setPower(int, int, int, int); float readCH1(int); float readCH2(int); float readCH3(int); float readCH4(int); void readCH5(void); //Declare Global Variables int IC1Capture1, IC1Capture2, IC2Capture1, IC2Capture2, IC3Capture1, IC3Capture2, IC4Capture1, IC4Capture2, IC5Capture1, IC5Capture2; int CH1count,CH2count, CH3count, CH4count, CH5count, CH1value, CH2value, CH3value, CH4value, CH5value, CH5status; void initializePWMoutput(void) { int pulseperiod = 4629; int pulsemin = 280; // Configure Output Functions (Table 10-4) RPOR5bits.RP11R = 18; // Assign OC1 to Pin RP11 (RD0) RPOR12bits.RP24R = 19; // Assign OC2 to Pin RP24 (RD1) RPOR11bits.RP23R = 20; // Assign OC3 to Pin RP23 (RD2) RPOR11bits.RP22R = 21; // Assign OC4 to Pin RP22 (RD3) //Set up OC1 OC1CON1 = 0x0000; //Clear control registers OC1CON2 = 0x0000; //Clear control registers OC1RS = pulsemin; //Load secondary register with initial pulse value OC1R = pulsemin; //Load primary register with initial pulse value OC1CON1bits.OCTSEL = 0b000; //Select Timer 2 as source OC1CON2bits.SYNCSEL = 0b01100; //Select Timer 2 as sync OC1CON1bits.OCM = 0b110; //Select Edge aligned PWM OC1CON2bits.OCTRIG = 0; //Set up OC2 OC2CON1 = 0x0000; //Clear control registers OC2CON2 = 0x0000; //Clear control registers OC2RS = pulsemin; //Load secondary register with initial pulse value OC2R = pulsemin; //Load primary register with initial pulse value OC2CON1bits.OCTSEL = 0b000; //Select Timer 2 as source OC2CON2bits.SYNCSEL = 0b01100; //Select Timer 2 as sync OC2CON1bits.OCM = 0b110; //Select Edge aligned PWM OC2CON2bits.OCTRIG = 0; //Set up OC3 OC3CON1 = 0x0000; //Clear control registers OC3CON2 = 0x0000; //Clear control registers OC3RS = pulsemin; //Load secondary register with initial pulse value OC3R = pulsemin; //Load primary register with initial pulse value OC3CON1bits.OCTSEL = 0b000; //Select Timer 2 as source OC3CON2bits.SYNCSEL = 0b01100; //Select Timer 2 as sync OC3CON1bits.OCM = 0b110; //Select Edge aligned PWM OC3CON2bits.OCTRIG = 0; //Set up OC4 OC4CON1 = 0x0000; //Clear control registers OC4CON2 = 0x0000; //Clear control registers OC4RS = pulsemin; //Load secondary register with initial pulse value OC4R = pulsemin; //Load primary register with initial pulse value OC4CON1bits.OCTSEL = 0b000; //Select Timer 2 as source OC4CON2bits.SYNCSEL = 0b01100; //Select Timer 2 as sync OC4CON1bits.OCM = 0b110; //Select Edge aligned PWM OC4CON2bits.OCTRIG = 0; //Set up Timer2, our timer for output PWM TMR2 = 0; //Set Timer2 to 0 PR2 = pulseperiod; //Load number of increments in period T2CONbits.TCKPS = 0b10; //Prescale value is 64 IFS0bits.T2IF = 0; //Clear Timer2 interrupt flag IEC0bits.T2IE = 1; //Enable Timer2 interrupts T2CONbits.TON = 1; //Turn Timer2 on } void initializePWMcapture(void) { // Configure Output Functions (Table 10-4) RPINR7bits.IC1R = 2; //Assign Input Capture 1 to RP2 (RD8) RPINR7bits.IC2R = 4; //Assign Input Capture 2 to RP4 (RD9) RPINR8bits.IC3R = 3; //Assign Input Capture 3 to RP3 (RD10) RPINR8bits.IC4R = 12; //Assign Input Capture 4 to RP12 (RD11) RPINR9bits.IC5R = 42; //Assign Input Capture 5 to RPI42 (RD12) //Initalize IC1 TRISDbits.TRISD8 = 1; //Set RD8 to input IC1CON1bits.ICM = 0b000; //This should reset the overflow condition flag, reset the FIFO to empty, and reset the prescale count IC1CON1bits.ICTSEL = 0b010; //Select Timer4 as timer IC1CON1bits.ICM = 0b01; //Capture timer value on every edge IC1CON1bits.ICI = 0b00; //Interrupt on every capture event IC1CON2bits.SYNCSEL = 0b01110; //Sync with Timer4 IC1CON2bits.ICTRIG = 0; //Clear trigger bit for synchronous mode. IEC0bits.IC1IE = 1; //Enable IC1 interrupt IFS0bits.IC1IF = 0; //Set interrupt flag status to 0 //Initalize IC2 TRISDbits.TRISD9 = 1; //Set RD9 to input IC2CON1bits.ICM = 0b000; //This should reset the overflow condition flag, reset the FIFO to empty, and reset the prescale count IC2CON1bits.ICTSEL = 0b010; //Select Timer4 as timer IC2CON1bits.ICM = 0b01; //Capture timer value on every edge IC2CON1bits.ICI = 0b00; //Interrupt on every capture event IC2CON2bits.SYNCSEL = 0b01110; //Sync with Timer4 IC2CON2bits.ICTRIG = 0; //Clear trigger bit for synchronous mode. IEC0bits.IC2IE = 1; //Enable IC2 interrupt IFS0bits.IC2IF = 0; //Set interrupt flag status to 0 //Initialize IC3 TRISDbits.TRISD10 = 1; //Set RD10 to input IC3CON1bits.ICM = 0b000; //This should reset the overflow condition flag, reset the FIFO to empty, and reset the prescale count IC3CON1bits.ICTSEL = 0b010; //Select Timer4 as timer IC3CON1bits.ICM = 0b01; //Capture timer value on every edge IC3CON1bits.ICI = 0b00; //Interrupt on every capture event IC3CON2bits.SYNCSEL = 0b01110; //Sync with Timer4 IC3CON2bits.ICTRIG = 0; //Clear trigger bit for synchronous mode. IEC2bits.IC3IE = 1; //Enable IC3 interrupt IFS2bits.IC3IF = 0; //Set interrupt flag status to 0 //Initialize IC4 TRISDbits.TRISD11 = 1; //Set RD11 to input IC4CON1bits.ICM = 0b000; //This should reset the overflow condition flag, reset the FIFO to empty, and reset the prescale count IC4CON1bits.ICTSEL = 0b010; //Select Timer4 as timer IC4CON1bits.ICM = 0b01; //Capture timer value on every edge IC4CON1bits.ICI = 0b00; //Interrupt on every capture event IC4CON2bits.SYNCSEL = 0b01110; //Sync with Timer4 IC4CON2bits.ICTRIG = 0; //Clear trigger bit for synchronous mode. IEC2bits.IC4IE = 1; //Enable IC5 interrupt IFS2bits.IC4IF = 0; //Set interrupt flag status to 0 //Initialize IC5 TRISDbits.TRISD12 = 1; //Set RD12 to input IC5CON1bits.ICM = 0b000; //This should reset the overflow condition flag, reset the FIFO to empty, and reset the prescaler count IC5CON1bits.ICTSEL = 0b010; //Select Timer4 as timer IC5CON1bits.ICM = 0b01; //Capture timer value on every edge IC5CON1bits.ICI = 0b00; //Interrupt on every capture event IC5CON2bits.SYNCSEL = 0b01110; //Sync with Timer4 IC5CON2bits.ICTRIG = 0; //Clear trigger bit for synchronous mode. IEC2bits.IC5IE = 1; //Enable IC5 interrupt IFS2bits.IC5IF = 0; //Set interrupt flag status to 0 //Set up Timer4, our clock for PWM //IFS1bits.T4IF = 0; // Commented out because I couldn't think of a reason to need the interrupt //IEC1bits.T4IE = 1; // Enable Timer4 Compare interrupts T4CONbits.TON = 1; // Start Timer2 with assumed settings T4CONbits.TCKPS = 0b10; // Timer4 Prescale value = 64 TMR4 = 0; // Set value of Timer4 to 0 } void __attribute__((interrupt, shadow, no_auto_psv)) _IC1Interrupt() { IFS0bits.IC1IF = 0; //Reset respective interrupt flag if (PORTDbits.RD8 == 1) //If the input is high, start count { IC1Capture1 = IC1BUF; //Load the start value from the capture buffer } else if (PORTDbits.RD8 == 0) //If the input is low, end count { IC1Capture2 = IC1BUF; //Load the end value from the capture buffer } CH1count = (IC1Capture2 - IC1Capture1); //Running time is ent time minus start time if (CH1count < 0) //Verify integrity of count {CH1count = CH1count + 4619;} } void __attribute__((interrupt, shadow, no_auto_psv)) _IC2Interrupt() { IFS0bits.IC2IF = 0; //Reset respective interrupt flag if (PORTDbits.RD9 == 1) { IC2Capture1 = IC2BUF; } else if (PORTDbits.RD9 == 0) { IC2Capture2 = IC2BUF; } CH2count = (IC2Capture2 - IC2Capture1); if (CH2count < 0) //Verify integrity of count CH2count = CH2count; } void __attribute__((interrupt, shadow, no_auto_psv)) _IC3Interrupt() { IFS2bits.IC3IF = 0; //Reset respective interrupt flag if (PORTDbits.RD10 == 1) { IC3Capture1 = IC3BUF; } else if (PORTDbits.RD10 == 0) { IC3Capture2 = IC3BUF; } CH3count = (IC3Capture2 - IC3Capture1); if (CH3count < 0) //Verify integrity of count CH3count = CH3count + 4619; } void __attribute__((interrupt, shadow, no_auto_psv)) _IC4Interrupt() { IFS2bits.IC4IF = 0; //Reset respective interrupt flag if (PORTDbits.RD11 == 1) { IC4Capture1 = IC4BUF; } else if (PORTDbits.RD11 == 0) { IC4Capture2 = IC4BUF; } CH4count = (IC4Capture2 - IC4Capture1); if (CH4count < 0) //Verify integrity of count CH4count = CH4count + 4619; } void __attribute__((interrupt, shadow, no_auto_psv)) _IC5Interrupt() { IFS2bits.IC5IF = 0; //Reset respective interrupt flag if (PORTDbits.RD12 == 1) { IC5Capture1 = IC5BUF; } else if (PORTDbits.RD12 == 0) { IC5Capture2 = IC5BUF; } CH5count = (IC5Capture2 - IC5Capture1); if (CH5count < 0) //Verify integrity of count CH5count = CH5count + 4619; } void __attribute__((interrupt, shadow, no_auto_psv)) _T2Interrupt() { IFS0bits.T2IF = 0; } void __attribute__((interrupt, shadow, no_auto_psv)) _T4Interrupt() { IFS1bits.T4IF = 0; } void setPower(int one, int two, int three, int four) //Function takes motor thrust commands from 0 to 100% and outputs OCxR register value { OC1R = (one) + 280; //Scale up the percentage to register value OC2R = (two) + 280; OC3R = (three) + 280; OC4R = (four) + 280; } float readCH1(int count) //Takes captured value and translates it to percentage 0 to 100 { float value = 0; //Placeholder variable if (count > 500 || count < 250) //Check intergrity of value, if out of 6-10.5% range, just write it as low value, 0% { value = 0; } else //If it's good, compute its percentage range { value = 0.510126*count - 145.38591; } return value; //Return that the percentage } float readCH2(int count) //Takes captured value and translates it to percentage 0 to 100 { float value = 0; //Placeholder variable if (count > 500 || count < 250) //Check intergrity of value, if out of 6-10.5% range, just write it as low value, 0% { value = 0; } else //If it's good, compute its percentage range { value = 0.50505051*count - 139.39394; } return value; //Return that the percentage } float readCH3(int count) //Takes captured value and translates it to percentage 0 to 100 { float value = 0; //Placeholder variable if (count > 500 || count < 250) //Check intergrity of value, if out of 6-10.5% range, just write it as low value, 0% { value = 0; } else //If it's good, compute its percentage range { value = 0.50761421*count - 141.62437; } return value; //Return that the percentage } float readCH4(int count) //Takes captured value and translates it to percentage 0 to 100 { float value = 0; //Placeholder variable if (count > 500 || count < 250) //Check intergrity of value, if out of 6-10.5% range, just write it as low value, 0% { value = 0; } else //If it's good, compute its percentage range { value = 0.51282051*count - 144.61538; } return value; //Return that the percentage } void readCH5(void) { if (CH5count > 500 && CH5count < 530) { CH5status = 1; } else if (CH5count < 400 && CH5count > 230) { CH5status = 0; } } void getPWM(void) { CH1value = readCH1(CH1count); //Read in the input channels CH2value = readCH1(CH2count); CH3value = readCH1(CH3count); CH4value = readCH1(CH4count); readCH5(); }